package controller;

import model.ChessboardModel;
import view.ChessboardView;
import model.QueenModel;
import view.QueenView;
import view.EditChessboardView;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import jpl.Query;

/**
 * Controlador del tablero y encagado de enviar consultas de solución a prolog.
 * @author Samuel Chávez, Axel Mayorga
 */
public class ChessboardController {
    public ChessboardView view;
    public ChessboardModel model;
    private EditChessboardView ecView;
    private ArrayList<ChessboardModel> solutions;
    private int currentSolution;
    Brain b = new Brain();
        
    public ChessboardController(ChessboardView view, ChessboardModel model){
        this.view = view;
        this.model = model;
        
        //Listeners
        this.view.addEditChessboardListener(new EditChessboardListener());
        this.view.addResetChessboardListener(new ResetChessboardListener());
        this.view.addSolveListener(new SolveListener());
        this.view.addPreviousSolutionListener(new PreviousSolutionListener());
        this.view.addNextSolutionListener(new NextSolutionListener());
        
        //Models
        this.view.setListCodePrologModel(this.model.getInstructions());
        
        solutions = new ArrayList<ChessboardModel>();
        currentSolution = 0;
    }
    
    /**
     * Se encarga de actualizar el tablero con el estado actual.
     */
    private void refresh()
    {
        QueenController qc;
        int noPositions = this.model.getHeight()*this.model.getWidth();
        this.view.cleanChessBoard();
        this.model.getQueens().clear();
        this.model.getQueenControllers().clear();
        
        int height=this.view.getChessboardHeight()/this.model.getHeight();
        int width=this.view.getChessboardWidth()/this.model.getWidth();
        
        //Recorre todas las posiciones para crear una ficha o posición
        for(int pos=0; pos<noPositions; pos++)
        {
            qc = new QueenController(new QueenView(width, height), new QueenModel(pos), this.model);
            qc.view.setLocation(width * (pos%this.model.getWidth()), height * (pos/this.model.getWidth()));
            this.view.addToChessboard(qc.view);
            this.model.getQueenControllers().add(qc);
                    
            //Si hay soluciones entonces las muestra en el tablero
            if(!solutions.isEmpty() && currentSolution<solutions.size())
            {
                if(solutions.get(currentSolution).getQueens().contains(pos))
                {
                    qc.view.setImage(qc.IMAGE_QUEEN);
                    this.model.addQueenAt(pos);
                }
            }
        }
    }
    
    //MVC Listener
    
    /**
     * Acción para el boton de editar tablero
     */
    class EditChessboardListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            ecView = new EditChessboardView();
            ecView.addOkButtonListener(new OkEditChessboardListener());
            if(ecView.showDialog(view, "Edit Chessboard"))
            {
                model.setHeight(ecView.getChessboardHeight());
                model.setWidth(ecView.getChessboardWidth());
                model.setkQueen(ecView.getChessboardQueens());
                currentSolution = 0;
                solutions.clear();
                refresh();
            }
        }
    }
    
    /**
     * Acción utilizada para el botón de Ok del dialog para editar el tablero
     */
    class OkEditChessboardListener implements ActionListener
    {
        @Override
        public void actionPerformed(ActionEvent e) {
            int height = ecView.getChessboardHeight();
            int width = ecView.getChessboardWidth();
            int queens = ecView.getChessboardQueens();
            boolean success = true;
            
            if(height==0)
            {
                ecView.showErrorMessageHeight("El alto debe ser mayor a cero."); 
                success = false;
            }
            
            if(width==0)
            {
                ecView.showErrorMessageWidth("El ancho debe ser mayor a cero.");
                success = false;
            }
        
            if(queens>=(height*width))
            {
                ecView.showErrorMessageQueens("El número de reinas, debe ser menor al número de casillas.");
                success = false;
            }
        
            if(success)
            {
                ecView.setChessboardVisible(false);
            }
        }
    }
    
    /**
     * Acción utilizada para resetear el tablero
     */
    class ResetChessboardListener implements ActionListener
    {
        @Override
        public void actionPerformed(ActionEvent e) {
            currentSolution = 0;
            solutions.clear();
            refresh();
        }
    }
     
    /**
     * Acción utilizada para el botón de solución
     */
    class SolveListener implements ActionListener
    {
        @Override
        public void actionPerformed(ActionEvent e) 
        {
            String sQuery = UtilityManager.getQuerySol(model);
            model.addInstructionAt(sQuery);
            solutions = UtilityManager.findChessboardState(b.query(sQuery), ((model.getHeight()>7 || model.getWidth()>7 || model.getkQueen()>7)?true:false));
            currentSolution = 0;
            
            if(solutions.isEmpty())
            {
                view.setEnabledPrevSolution(false);
                view.setEnabledNextSolution(false);
                model.addInstructionAt("No solution.");
            }
            else
            {
                view.setEnabledPrevSolution(false);
                view.setEnabledNextSolution((solutions.size()>1?true:false));
            }
            
            refresh();
        }
    }
    
    /**
     * Acción utilizada para moverse a la solución anterior
     */
    class PreviousSolutionListener implements ActionListener
    {
        @Override
        public void actionPerformed(ActionEvent e) {
            if(!solutions.isEmpty() && currentSolution>0)
            {
                view.setEnabledNextSolution(true);
                currentSolution--;
                refresh();
            }
            else
            {
                view.setEnabledPrevSolution(false);
            }
        }
    }
    
    /**
     * Acción utilizada para moverse a la solución siguiente
     */
    class NextSolutionListener implements ActionListener
    {
        @Override
        public void actionPerformed(ActionEvent e) {
            if(!solutions.isEmpty() && currentSolution<solutions.size()-1)
            {
                view.setEnabledPrevSolution(true);
                currentSolution++;
                refresh();
            }
            else
            {
                view.setEnabledNextSolution(false);
            }
        }
    }
    //End MVC Listener
    
}
